package com.wuzuqing.android.eightdiagrams.term;

import java.util.*;

public class Lunar {
    public static String[] JIE_QI = new String[]{"冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满",
            "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪"};
    public static String[] JIE_QI_IN_USE = new String[]{"DA_XUE", "冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明",
            "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "DONG_ZHI"
            , "XIAO_HAN", "DA_HAN", "LI_CHUN", "YU_SHUI", "JING_ZHE"};

    public int year;
    public int month;
    public int day;
    public int hour;
    public int minute;
    public int second;
    public int timeGanIndex;//: gz.timeGanIndex,
    public int timeZhiIndex;//: gz.timeZhiIndex,
    public int dayGanIndex;//: gz.dayGanIndex,
    public int dayZhiIndex;//: gz.dayZhiIndex,
    public int dayGanIndexExact;//: gz.dayGanIndexExact,
    public int dayZhiIndexExact;//: gz.dayZhiIndexExact,
    public int dayGanIndexExact2;//: gz.dayGanIndexExact2,
    public int dayZhiIndexExact2;//: gz.dayZhiIndexExact2,
    public int monthGanIndex;//: gz.monthGanIndex,
    public int monthZhiIndex;//: gz.monthZhiIndex,
    public int monthGanIndexExact;//: gz.monthGanIndexExact,
    public int monthZhiIndexExact;//: gz.monthZhiIndexExact,
    public int yearGanIndex;//: gz.yearGanIndex,
    public int yearZhiIndex;//: gz.yearZhiIndex,
    public int yearGanIndexByLiChun;//: gz.yearGanIndexByLiChun,
    public int yearZhiIndexByLiChun;//: gz.yearZhiIndexByLiChun,
    public int yearGanIndexExact;//: gz.yearGanIndexExact,
    public int yearZhiIndexExact;//: gz.yearZhiIndexExact,
    public int weekIndex;//: gz.weekIndex,
    public List<String> jieQiList = new ArrayList<>();
    public Map<String, Solar> jieQi = new HashMap<>();
    public Solar solar;
    public LunarYear lunarYear;
    public EightChar eightChar;

    public Lunar(int year, int month, int day, int hour, int minute, int second, Solar solar, LunarYear lunarYear) {
        this.year = year;
        this.month = month;
        this.day = day;
        this.hour = hour;
        this.minute = minute;
        this.second = second;
        this.solar = solar;
        this.lunarYear = lunarYear;
    }

    public static Lunar fromYmd(int y, int m, int d) {
        return _fromYmdHms(y, m, d, 0, 0, 0);
    }

    public static Lunar fromDate(ExactDate date) {
        return _fromDate(date);
    }

    private static boolean diff(String date1, String date2, String fh) {
        switch (fh) {
            case ">":
                return date1.compareTo(date2) > 0;
            case ">=":
                return date1.compareTo(date2) >= 0;
            case "<":
                return date1.compareTo(date2) < 0;
            case "<=":
                return date1.compareTo(date2) <= 0;
            default:
                return date1.compareTo(date2) == 0;
        }
    }

    public static Lunar _fromDate(ExactDate date) {
        ExactDate c = ExactDate.fromYmd(date.getYear(), date.getMonth(), date.getDate());
        long solarTime = c.getTime();
        int lunarYear = 0;
        int lunarMonth = 0;
        int lunarDay = 0;
        int y = c.getFullYear();
        LunarYear ly = LunarYear.fromYear(y);
        List<LunarMonth> lms = ly.getMonths();

        for (int i = 0, j = lms.size(); i < j; i++) {
            LunarMonth m = lms.get(i);

            // 初一
            ExactDate firstDay = Solar.fromJulianDay(m.getFirstJulianDay()).getCalendar();
            firstDay.setTime(0, 0, 0, 0);
            int days = (int) Math.floor((solarTime * 1f - firstDay.getTime()) / MS_PER_DAY);
            if (days < m.getDayCount()) {
                lunarYear = m.getYear();
                lunarMonth = m.getMonth();
                lunarDay = days + 1;
                break;
            }
        }
        return _new(lunarYear, lunarMonth, lunarDay, date.getHours(), date.getMinutes(), date.getSeconds(),
                Solar.fromDate(date), ly);
    }

    public static final int MS_PER_DAY = 86400000;

    public void _computeJieQi() {
        List<Double> julianDays = lunarYear.getJieQiJulianDays();
        for (int i = 0, j = Lunar.JIE_QI_IN_USE.length; i < j; i++) {
            String key = Lunar.JIE_QI_IN_USE[i];
            jieQiList.add(key);
            jieQi.put(key, Solar.fromJulianDay(julianDays.get(i)));
        }
    }

    public void _computeYear() {
        //以正月初一开始
        int offset = year - 4;
        int yearGanIndex = offset % 10;
        int yearZhiIndex = offset % 12;

        if (yearGanIndex < 0) {
            yearGanIndex += 10;
        }

        if (yearZhiIndex < 0) {
            yearZhiIndex += 12;
        }

        //以立春作为新一年的开始的干支纪年
        int g = yearGanIndex;
        int z = yearZhiIndex;

        //精确的干支纪年，以立春交接时刻为准
        int gExact = yearGanIndex;
        int zExact = yearZhiIndex;

        int solarYear = solar.getYear();
        String solarYmd = solar.toYmd();
        String solarYmdHms = solar.toYmdHms();

        //获取立春的阳历时刻
        Solar liChun = jieQi.get("立春");
        if (liChun.getYear() != solarYear) {
            liChun = jieQi.get("LI_CHUN");
        }
        String liChunYmd = liChun.toYmd();
        String liChunYmdHms = liChun.toYmdHms();

        //阳历和阴历年份相同代表正月初一及以后
        if (year == solarYear) {
            //立春日期判断
            //if () {
            if (diff(solarYmd, liChunYmd, "<")) {
                g--;
                z--;
            }
            //立春交接时刻判断
            if (diff(solarYmdHms, liChunYmdHms, "<")) {
                gExact--;
                zExact--;
            }
        } else if (year < solarYear) {
            if (diff(solarYmd, liChunYmd, ">=")) {
                g++;
                z++;
            }
            if (diff(solarYmdHms, liChunYmdHms, ">=")) {
                gExact++;
                zExact++;
            }
        }
        this.yearGanIndex = yearGanIndex;
        this.yearZhiIndex = yearZhiIndex;
        this.yearGanIndexByLiChun = (g < 0 ? g + 10 : g) % 10;
        this.yearZhiIndexByLiChun = (z < 0 ? z + 12 : z) % 12;
        this.yearGanIndexExact = (gExact < 0 ? gExact + 10 : gExact) % 10;
        this.yearZhiIndexExact = (zExact < 0 ? zExact + 12 : zExact) % 12;
    }

    public void _computeMonth() {
        int i;
        Solar end, start = null;
        int size = Lunar.JIE_QI_IN_USE.length;

        //序号：大雪以前-3，大雪到小寒之间-2，小寒到立春之间-1，立春之后0
        int index = -3;
        for (i = 0; i < size; i += 2) {
            end = jieQi.get(Lunar.JIE_QI_IN_USE[i]);
            String ymd = solar.toYmd();
            String symd = null == start ? ymd : start.toYmd();
            if (diff(ymd, symd, ">=") && diff(ymd, end.toYmd(), "<")) {
                break;
            }
            start = end;
            index++;
        }
        int offset = (((yearGanIndexByLiChun + (index < 0 ? 1 : 0)) % 5 + 1) * 2) % 10;
        monthGanIndex = ((index < 0 ? index + 10 : index) + offset) % 10;
        monthZhiIndex = ((index < 0 ? index + 12 : index) + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12;

        start = null;
        index = -3;
        for (i = 0; i < size; i += 2) {
            end = jieQi.get(Lunar.JIE_QI_IN_USE[i]);
            String time = solar.toYmdHms();
            String stime = null == start ? time : start.toYmdHms();
            if (diff(time, stime, ">=") && diff(time, end.toYmdHms(), "<")) {
                break;
            }
            start = end;
            index++;
        }
        offset = (((yearGanIndexExact + (index < 0 ? 1 : 0)) % 5 + 1) * 2) % 10;
        monthGanIndexExact = ((index < 0 ? index + 10 : index) + offset) % 10;
        monthZhiIndexExact = ((index < 0 ? index + 12 : index) + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12;
    }

    ;

    public void _computeDay() {
        Solar noon = Solar.fromYmdHms(solar.getYear(), solar.getMonth(), solar.getDay(), 12, 0, 0);
        int offset = (int) (Math.floor(noon.getJulianDay()) - 11);


        int dayGanIndex = offset % 10;
        int dayZhiIndex = offset % 12;
        this.dayGanIndex = dayGanIndex;
        this.dayZhiIndex = dayZhiIndex;
        int dayGanExact = dayGanIndex;
        int dayZhiExact = dayZhiIndex;
        dayGanIndexExact2 = dayGanExact;
        dayZhiIndexExact2 = dayZhiExact;
        String hm = (hour < 10 ? "0" : "") + hour + ":" + (minute < 10 ? "0" : "") + minute;
        if (diff(hm, "23:00", ">=") && diff(hm, "23:59", "<=")) {
            dayGanExact++;
            if (dayGanExact >= 10) {
                dayGanExact -= 10;
            }
            dayZhiExact++;
            if (dayZhiExact >= 12) {
                dayZhiExact -= 12;
            }
        }
        dayGanIndexExact = dayGanExact;
        dayZhiIndexExact = dayZhiExact;
    }

    public void _computeTime() {
        // 23-01 0
        //1 2 1
        //3 4 2
        int timeZhiIndex = LunarUtil.getTimeZhiIndex((hour < 10 ? "0" : "") + hour + ":" + (minute < 10 ? "0" : "")
                + minute);
        this.timeZhiIndex = timeZhiIndex;
        timeGanIndex = (dayGanIndexExact % 5 * 2 + timeZhiIndex) % 10;
    }

    public void _computeWeek() {
        weekIndex = solar.getWeek();
    }

    public void _compute() {
        _computeJieQi();
        _computeYear();
        _computeMonth();
        _computeDay();
        _computeTime();
        _computeWeek();
    }

    public static Lunar _fromYmdHms(int lunarYear, int lunarMonth, int lunarDay, int hour, int minute, int second) {
        LunarYear y = LunarYear.fromYear(lunarYear);
        LunarMonth m = y.getMonth(lunarMonth);
        if (null == m) {
            throw new IllegalArgumentException("wrong lunar year " + lunarYear + " month " + lunarMonth);
        }
        if (lunarDay < 1) {
            throw new IllegalArgumentException("lunar day must bigger than 0");
        }
        int days = m.getDayCount();
        if (lunarDay > days) {
            throw new IllegalArgumentException("only " + days + " days in lunar year " + lunarYear + " month " + lunarMonth);
        }
        Solar noon = Solar.fromJulianDay(m.getFirstJulianDay() + lunarDay - 1);
        Solar solar = Solar.fromYmdHms(noon.getYear(), noon.getMonth(), noon.getDay(), hour, minute, second);
        return _new(lunarYear, lunarMonth, lunarDay, hour, minute, second, solar, y);
    }

    public static Lunar _new(int year, int month, int day, int hour, int minute, int second, Solar solar,
                             LunarYear ly) {
        Lunar lunar = new Lunar(year, month, day, hour, minute, second, solar, ly);
        lunar._compute();
        return lunar;
    }

    public int getYear() {
        return this.year;
    }

    public int getMonth() {
        return this.month;
    }

    public int getDay() {
        return this.day;
    }

    public int getHour() {
        return this.hour;
    }

    public int getMinute() {
        return this.minute;
    }

    public int getSecond() {
        return this.second;
    }

    public int getTimeGanIndex() {
        return this.timeGanIndex;
    }

    public int getTimeZhiIndex() {
        return this.timeZhiIndex;
    }

    public int getDayGanIndex() {
        return this.dayGanIndex;
    }

    public int getDayGanIndexExact() {
        return this.dayGanIndexExact;
    }

    public int getDayGanIndexExact2() {
        return this.dayGanIndexExact2;
    }

    public int getDayZhiIndex() {
        return this.dayZhiIndex;
    }

    public int getDayZhiIndexExact() {
        return this.dayZhiIndexExact;
    }

    public int getDayZhiIndexExact2() {
        return this.dayZhiIndexExact2;
    }

    public int getMonthGanIndex() {
        return this.monthGanIndex;
    }

    public int getMonthGanIndexExact() {
        return this.monthGanIndexExact;
    }

    public int getMonthZhiIndex() {
        return this.monthZhiIndex;
    }

    public int getMonthZhiIndexExact() {
        return this.monthZhiIndexExact;
    }

    public int getYearGanIndex() {
        return this.yearGanIndex;
    }

    public int getYearGanIndexByLiChun() {
        return this.yearGanIndexByLiChun;
    }

    public int getYearGanIndexExact() {
        return this.yearGanIndexExact;
    }

    public int getYearZhiIndex() {
        return this.yearZhiIndex;
    }

    public int getYearZhiIndexByLiChun() {
        return this.yearZhiIndexByLiChun;
    }

    public int getYearZhiIndexExact() {
        return this.yearZhiIndexExact;
    }

    public String getGan() {
        return this.getYearGan();
    }

    public String getZhi() {
        return this.getYearZhi();
    }

    public String getYearGan() {
        return LunarUtil.GAN[this.yearGanIndex + 1];
    }

    public String getYearGanByLiChun() {
        return LunarUtil.GAN[this.yearGanIndexByLiChun + 1];
    }

    public String getYearGanExact() {
        return LunarUtil.GAN[this.yearGanIndexExact + 1];
    }

    public String getYearZhi() {
        return LunarUtil.ZHI[this.yearZhiIndex + 1];
    }

    public String getYearZhiByLiChun() {
        return LunarUtil.ZHI[this.yearZhiIndexByLiChun + 1];
    }

    public String getYearZhiExact() {
        return LunarUtil.ZHI[this.yearZhiIndexExact + 1];
    }

    public String getYearInGanZhi() {
        return this.getYearGan() + this.getYearZhi();
    }

    public String getYearInGanZhiByLiChun() {
        return this.getYearGanByLiChun() + this.getYearZhiByLiChun();
    }

    public String getYearInGanZhiExact() {
        return this.getYearGanExact() + this.getYearZhiExact();
    }

    public String getMonthGan() {
        return LunarUtil.GAN[this.monthGanIndex + 1];
    }

    public String getMonthGanExact() {
        return LunarUtil.GAN[this.monthGanIndexExact + 1];
    }

    public String getMonthZhi() {
        return LunarUtil.ZHI[this.monthZhiIndex + 1];
    }

    public String getMonthZhiExact() {
        return LunarUtil.ZHI[this.monthZhiIndexExact + 1];
    }

    public String getMonthInGanZhi() {
        return this.getMonthGan() + this.getMonthZhi();
    }

    public String getMonthInGanZhiExact() {
        return this.getMonthGanExact() + this.getMonthZhiExact();
    }

    public String getDayGan() {
        return LunarUtil.GAN[this.dayGanIndex + 1];
    }

    public String getDayGanExact() {
        return LunarUtil.GAN[this.dayGanIndexExact + 1];
    }

    public String getDayGanExact2() {
        return LunarUtil.GAN[this.dayGanIndexExact2 + 1];
    }

    public String getDayZhi() {
        return LunarUtil.ZHI[this.dayZhiIndex + 1];
    }

    public String getDayZhiExact() {
        return LunarUtil.ZHI[this.dayZhiIndexExact + 1];
    }

    public String getDayZhiExact2() {
        return LunarUtil.ZHI[this.dayZhiIndexExact2 + 1];
    }

    public String getDayInGanZhi() {
        return this.getDayGan() + this.getDayZhi();
    }

    public String getDayInGanZhiExact() {
        return this.getDayGanExact() + this.getDayZhiExact();
    }

    public String getDayInGanZhiExact2() {
        return this.getDayGanExact2() + this.getDayZhiExact2();
    }

    public String getTimeGan() {
        return LunarUtil.GAN[this.timeGanIndex + 1];
    }

    public String getTimeZhi() {
        return LunarUtil.ZHI[this.timeZhiIndex + 1];
    }

    public String getTimeInGanZhi() {
        return this.getTimeGan() + this.getTimeZhi();
    }

    public String getShengxiao() {
        return this.getYearShengXiao();
    }

    public String getYearShengXiao() {
        return LunarUtil.SHENGXIAO[this.yearZhiIndex + 1];
    }

    public String getYearShengXiaoByLiChun() {
        return LunarUtil.SHENGXIAO[this.yearZhiIndexByLiChun + 1];
    }

    public String getYearShengXiaoExact() {
        return LunarUtil.SHENGXIAO[this.yearZhiIndexExact + 1];
    }

    public String getMonthShengXiao() {
        return LunarUtil.SHENGXIAO[this.monthZhiIndex + 1];
    }

    public String getMonthShengXiaoExact() {
        return LunarUtil.SHENGXIAO[this.monthZhiIndexExact + 1];
    }

    public String getDayShengXiao() {
        return LunarUtil.SHENGXIAO[this.dayZhiIndex + 1];
    }

    public String getTimeShengXiao() {
        return LunarUtil.SHENGXIAO[this.timeZhiIndex + 1];
    }

    public String getYearInChinese() {
        String y = (this.year + "");
        StringBuilder s = new StringBuilder();
        char zero = "0".charAt(0);
        for (int i = 0, j = y.length(); i < j; i++) {
            s.append(LunarUtil.NUMBER[y.charAt(i) - zero]);
        }
        return s.toString();
    }

    public String getMonthInChinese() {
        int month = this.month;
        return (month < 0 ? "闰" : "") + LunarUtil.MONTH[Math.abs(month)];
    }

    public String getDayInChinese() {
        return LunarUtil.DAY[this.day];
    }

    public String getPengZuGan() {
        return LunarUtil.PENGZU_GAN[this.dayGanIndex + 1];
    }

    public String getPengZuZhi() {
        return LunarUtil.PENGZU_ZHI[this.dayZhiIndex + 1];
    }

    public String getPositionXi() {
        return this.getDayPositionXi();
    }

    public String getPositionXiDesc() {
        return this.getDayPositionXiDesc();
    }

    public String getPositionYangGui() {
        return this.getDayPositionYangGui();
    }

    public String getPositionYangGuiDesc() {
        return this.getDayPositionYangGuiDesc();
    }

    public String getPositionYinGui() {
        return this.getDayPositionYinGui();
    }

    public String getPositionYinGuiDesc() {
        return this.getDayPositionYinGuiDesc();
    }

    public String getPositionFu() {
        return this.getDayPositionFu();
    }

    public String getPositionFuDesc() {
        return this.getDayPositionFuDesc();
    }

    public String getPositionCai() {
        return this.getDayPositionCai();
    }

    public String getPositionCaiDesc() {
        return this.getDayPositionCaiDesc();
    }

    public String getDayPositionXi() {
        return LunarUtil.POSITION_XI[this.dayGanIndex + 1];
    }

    public String getDayPositionXiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getDayPositionXi());
    }

    public String getDayPositionYangGui() {
        return LunarUtil.POSITION_YANG_GUI[this.dayGanIndex + 1];
    }

    public String getDayPositionYangGuiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getDayPositionYangGui());
    }

    public String getDayPositionYinGui() {
        return LunarUtil.POSITION_YIN_GUI[this.dayGanIndex + 1];
    }

    public String getDayPositionYinGuiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getDayPositionYinGui());
    }

    public String getDayPositionFu() {
        return LunarUtil.POSITION_FU[this.dayGanIndex + 1];
    }

    public String getDayPositionFuDesc() {
        return LunarUtil.POSITION_DESC.get(this.getDayPositionFu());
    }

    public String getDayPositionCai() {
        return LunarUtil.POSITION_CAI[this.dayGanIndex + 1];
    }

    public String getDayPositionCaiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getDayPositionCai());
    }

    public String getTimePositionXi() {
        return LunarUtil.POSITION_XI[this.timeGanIndex + 1];
    }

    public String getTimePositionXiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getTimePositionXi());
    }

    public String getTimePositionYangGui() {
        return LunarUtil.POSITION_YANG_GUI[this.timeGanIndex + 1];
    }

    public String getTimePositionYangGuiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getTimePositionYangGui());
    }

    public String getTimePositionYinGui() {
        return LunarUtil.POSITION_YIN_GUI[this.timeGanIndex + 1];
    }

    public String getTimePositionYinGuiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getTimePositionYinGui());
    }

    public String getTimePositionFu() {
        return LunarUtil.POSITION_FU[this.timeGanIndex + 1];
    }

    public String getTimePositionFuDesc() {
        return LunarUtil.POSITION_DESC.get(this.getTimePositionFu());
    }

    public String getTimePositionCai() {
        return LunarUtil.POSITION_CAI[this.timeGanIndex + 1];
    }

    public String getTimePositionCaiDesc() {
        return LunarUtil.POSITION_DESC.get(this.getTimePositionCai());
    }

    public String getChong() {
        return this.getDayChong();
    }

    public String getChongGan() {
        return this.getDayChongGan();
    }

    public String getChongGanTie() {
        return this.getDayChongGanTie();
    }

    public String getChongShengXiao() {
        return this.getDayChongShengXiao();
    }

    public String getChongDesc() {
        return this.getDayChongDesc();
    }

    public String getSha() {
        return this.getDaySha();
    }

    public String getDayChong() {
        return LunarUtil.CHONG.get(this.getDayZhi());
    }

    public String getDayChongGan() {
        return LunarUtil.CHONG_GAN.get(this.getDayGan());
    }

    public String getDayChongGanTie() {
        return LunarUtil.CHONG_GAN_TIE.get(this.getDayGan());
    }

    public String getDayChongShengXiao() {
        String chong = this.getChong();
        for (int i = 0, j = LunarUtil.ZHI.length; i < j; i++) {
            if (chong.equals(LunarUtil.ZHI[i])) {
                return LunarUtil.SHENGXIAO[i];
            }
        }
        return "";
    }

    public String getDayChongDesc() {
        return "(" + this.getDayChongGan() + this.getDayChong() + ")" + this.getDayChongShengXiao();
    }

    public String getDaySha() {
        return LunarUtil.SHA.get(this.getDayZhi());
    }

    public String getTimeChong() {
        return LunarUtil.CHONG.get(this.getTimeZhi());
    }

    public String getTimeChongGan() {
        return LunarUtil.CHONG_GAN.get(this.getTimeGan());
    }

    public String getTimeChongGanTie() {
        return LunarUtil.CHONG_GAN_TIE.get(this.getTimeGan());
    }

    public String getTimeChongShengXiao() {
        String chong = this.getTimeChong();
        for (int i = 0, j = LunarUtil.ZHI.length; i < j; i++) {
            if (LunarUtil.ZHI[i].equals(chong)) {
                return LunarUtil.SHENGXIAO[i];
            }
        }
        return "";
    }

    public String getTimeChongDesc() {
        return "(" + this.getTimeChongGan() + this.getTimeChong() + ")" + this.getTimeChongShengXiao();
    }

    public String getTimeSha() {
        return LunarUtil.SHA.get(this.getTimeZhi());
    }

    public String getYearNaYin() {
        return LunarUtil.NAYIN.get(this.getYearInGanZhi());
    }

    public String getMonthNaYin() {
        return LunarUtil.NAYIN.get(this.getMonthInGanZhi());
    }

    public String getDayNaYin() {
        return LunarUtil.NAYIN.get(this.getDayInGanZhi());
    }

    public String getTimeNaYin() {
        return LunarUtil.NAYIN.get(this.getTimeInGanZhi());
    }

    public String getSeason() {
        return LunarUtil.SEASON[Math.abs(this.month)];
    }


    public String _convertJieQi(String name) {
        String jq = name;
        if ("DONG_ZHI".equals(jq)) {
            jq = "冬至";
        } else if ("DA_HAN".equals(jq)) {
            jq = "大寒";
        } else if ("XIAO_HAN".equals(jq)) {
            jq = "小寒";
        } else if ("LI_CHUN".equals(jq)) {
            jq = "立春";
        } else if ("DA_XUE".equals(jq)) {
            jq = "大雪";
        } else if ("YU_SHUI".equals(jq)) {
            jq = "雨水";
        } else if ("JING_ZHE".equals(jq)) {
            jq = "惊蛰";
        }
        return jq;
    }

    public String getJie() {
        String jie = "";
        for (int i = 1, j = Lunar.JIE_QI.length; i < j; i += 2) {
            String key = Lunar.JIE_QI[i];
            Solar d = this.jieQi.get(key);
            if (d.getYear() == this.solar.getYear() && d.getMonth() == this.solar.getMonth() && d.getDay() ==
                    this.solar.getDay()) {
                jie = key;
                break;
            }
        }
        return this._convertJieQi(jie);
    }

    public String getQi() {
        Solar d;
        String qi = "";
        for (int i = 0, j = Lunar.JIE_QI.length; i < j; i += 2) {
            String key = Lunar.JIE_QI[i];
            d = this.jieQi.get(key);
            if (d.getYear() == this.solar.getYear() && d.getMonth() == this.solar.getMonth() && d.getDay()
                    == this.solar.getDay()) {
                qi = key;
                break;
            }
        }
        return this._convertJieQi(qi);
    }

    public String getJieQi() {
        String name = "";
        for (String key : this.jieQi.keySet()) {
            Solar d = this.jieQi.get(key);
            if (d.getYear() == this.solar.getYear() && d.getMonth() == this.solar.getMonth() && d.getDay() ==
                    this.solar.getDay()) {
                name = key;
                break;
            }
        }
        return this._convertJieQi(name);
    }

    public int getWeek() {
        return this.weekIndex;
    }

    public String getWeekInChinese() {
        return SolarUtil.WEEK[this.getWeek()];
    }

    public String getXiu() {
        return LunarUtil.XIU.get(this.getDayZhi() + this.getWeek());
    }

    public String getXiuLuck() {
        return LunarUtil.XIU_LUCK.get(this.getXiu());
    }

    public String getXiuSong() {
        return LunarUtil.XIU_SONG.get(this.getXiu());
    }

    public String getZheng() {
        return LunarUtil.ZHENG.get(this.getXiu());
    }

    public String getAnimal() {
        return LunarUtil.ANIMAL.get(this.getXiu());
    }

    final public String animalsYear() {
        final String[] Animals = new String[]{"鼠", "牛", "虎", "兔", "龙", "蛇",
                "马", "羊", "猴", "鸡", "狗", "猪"};
        return Animals[(year - 4) % 12];
    }

    public String getGong() {
        return LunarUtil.GONG.get(this.getXiu());
    }

    public String getShou() {
        return LunarUtil.SHOU.get(this.getGong());
    }

    public List<String> getFestivals() {
        List<String> l = new ArrayList<>();
        String f = LunarUtil.FESTIVAL.get(this.month + "-" + this.day);
        if (f != null) {
            l.add(f);
        }
        if (Math.abs(this.month) == 12 && this.day >= 29 && this.year != this.next(1).getYear()) {
            l.add("除夕");
        }
        return l;
    }

    public List<String> getOtherFestivals() {
        List<String> l = new ArrayList<>();
        String[] fs = LunarUtil.OTHER_FESTIVAL.get(this.month + "-" + this.day);
        if (fs != null) {
            for (int i = 0, j = fs.length; i < j; i++) {
                l.add(fs[i]);
            }
        }
        return l;
    }

    public List<String> getBaZi() {
        EightChar bz = this.getEightChar();
        List<String> l = new ArrayList<>();
        l.add(bz.getYear());
        l.add(bz.getMonth());
        l.add(bz.getDay());
        l.add(bz.getTime());
        return l;
    }

    public List<String> getBaZiWuXing() {
        EightChar bz = this.getEightChar();
        List<String> l = new ArrayList<>();
        l.add(bz.getYearWuXing());
        l.add(bz.getMonthWuXing());
        l.add(bz.getDayWuXing());
        l.add(bz.getTimeWuXing());
        return l;
    }

    public List<String> getBaZiNaYin() {
        EightChar bz = this.getEightChar();
        List<String> l = new ArrayList<>();
        l.add(bz.getYearNaYin());
        l.add(bz.getMonthNaYin());
        l.add(bz.getDayNaYin());
        l.add(bz.getTimeNaYin());
        return l;
    }

    public List<String> getBaZiShiShenGan() {
        EightChar bz = this.getEightChar();
        List<String> l = new ArrayList<>();
        l.add(bz.getYearShiShenGan());
        l.add(bz.getMonthShiShenGan());
        l.add(bz.getDayShiShenGan());
        l.add(bz.getTimeShiShenGan());
        return l;
    }

    public List<String> getBaZiShiShenZhi() {
        EightChar bz = this.getEightChar();
        List<String> l = new ArrayList<>();
        l.add(bz.getYearShiShenZhi().get(0));
        l.add(bz.getMonthShiShenZhi().get(0));
        l.add(bz.getDayShiShenZhi().get(0));
        l.add(bz.getTimeShiShenZhi().get(0));
        return l;
    }

    public List<String> getBaZiShiShenYearZhi() {
        return this.getEightChar().getYearShiShenZhi();
    }

    public List<String> getBaZiShiShenMonthZhi() {
        return this.getEightChar().getMonthShiShenZhi();
    }

    public List<String> getBaZiShiShenDayZhi() {
        return this.getEightChar().getDayShiShenZhi();
    }

    public List<String> getBaZiShiShenTimeZhi() {
        return this.getEightChar().getTimeShiShenZhi();
    }

    public String getZhiXing() {
        int offset = this.dayZhiIndex - this.monthZhiIndex;
        if (offset < 0) {
            offset += 12;
        }
        return LunarUtil.ZHI_XING[offset + 1];
    }

    public String getDayTianShen() {
        String monthZhi = this.getMonthZhi();
        int offset = LunarUtil.ZHI_TIAN_SHEN_OFFSET.get(monthZhi);
        return LunarUtil.TIAN_SHEN[(this.dayZhiIndex + offset) % 12 + 1];
    }

    public String getTimeTianShen() {
        String dayZhi = this.getDayZhiExact();
        int offset = LunarUtil.ZHI_TIAN_SHEN_OFFSET.get(dayZhi);
        return LunarUtil.TIAN_SHEN[(this.timeZhiIndex + offset) % 12 + 1];
    }

    public String getDayTianShenType() {
        return LunarUtil.TIAN_SHEN_TYPE.get(this.getDayTianShen());
    }

    public String getTimeTianShenType() {
        return LunarUtil.TIAN_SHEN_TYPE.get(this.getTimeTianShen());
    }

    public String getDayTianShenLuck() {
        return LunarUtil.TIAN_SHEN_TYPE_LUCK.get(this.getDayTianShenType());
    }

    public String getTimeTianShenLuck() {
        return LunarUtil.TIAN_SHEN_TYPE_LUCK.get(this.getTimeTianShenType());
    }

    public String getDayPositionTai() {
        int offset = this.dayGanIndex - this.dayZhiIndex;
        if (offset < 0) {
            offset += 12;
        }
        return LunarUtil.POSITION_TAI_DAY[offset * 5 + this.dayGanIndex];
    }

    public String getMonthPositionTai() {
        int m = this.month;
        if (m < 0) {
            return "";
        }
        return LunarUtil.POSITION_TAI_MONTH[m - 1];
    }

    public List<String> getDayYi() {
        return LunarUtil.getDayYi(this.getMonthInGanZhiExact(), this.getDayInGanZhi());
    }

    public List<String> getDayJi() {
        return LunarUtil.getDayJi(this.getMonthInGanZhiExact(), this.getDayInGanZhi());
    }

    public List<String> getDayJiShen() {
        return LunarUtil.getDayJiShen(this.getMonth(), this.getDayInGanZhi());
    }

    public List<String> getDayXiongSha() {
        return LunarUtil.getDayXiongSha(this.getMonth(), this.getDayInGanZhi());
    }

    public List<String> getTimeYi() {
        return LunarUtil.getTimeYi(this.getDayInGanZhiExact(), this.getTimeInGanZhi());
    }

    public List<String> getTimeJi() {
        return LunarUtil.getTimeJi(this.getDayInGanZhiExact(), this.getTimeInGanZhi());
    }

    public String getYueXiang() {
        return LunarUtil.YUE_XIANG[this.day];
    }

    public NineStar getYearNineStar() {
        int index = -(this.year - 1900) % 9;
        if (index < 0) {
            index += 9;
        }
        return NineStar.fromIndex(index);
    }

    public NineStar getMonthNineStar() {
        int start = 2;
        String yearZhi = this.getYearZhi();
        if ("子午卯酉".indexOf(yearZhi) > -1) {
            start = 8;
        } else if ("辰戌丑未".indexOf(yearZhi) > -1) {
            start = 5;
        }
        // 寅月起，所以需要-2
        int monthIndex = this.monthZhiIndex - 2;
        if (monthIndex < 0) {
            monthIndex += 12;
        }
        int index = start - monthIndex - 1;
        while (index < 0) {
            index += 9;
        }
        return NineStar.fromIndex(index);
    }

    public NineStar getDayNineStar() {
        //顺逆
        String solarYmd = this.solar.toYmd();
        String yuShui = this.jieQi.get("雨水").toYmd();
        String guYu = this.jieQi.get("谷雨").toYmd();
        String xiaZhi = this.jieQi.get("夏至").toYmd();
        String chuShu = this.jieQi.get("处暑").toYmd();
        String shuangJiang = this.jieQi.get("霜降").toYmd();

        int start = 6;
        boolean asc = false;
        if (diff(solarYmd, this.jieQi.get("冬至").toYmd(), ">=") && diff(solarYmd, yuShui, "<")) {
            asc = true;
            start = 1;
        } else if (diff(solarYmd, yuShui, ">=") && diff(solarYmd, guYu, "<")) {
            asc = true;
            start = 7;
        } else if (diff(solarYmd, guYu, "<=") && diff(solarYmd, xiaZhi, "<")) {
            asc = true;
            start = 4;
        } else if (diff(solarYmd, xiaZhi, ">=") && diff(solarYmd, chuShu, "<")) {
            start = 9;
        } else if (diff(solarYmd, chuShu, ">=") && diff(solarYmd, shuangJiang, "<")) {
            start = 3;
        }
        int ganZhiIndex = LunarUtil.getJiaZiIndex(this.getDayInGanZhi()) % 9;
        int index = asc ? start + ganZhiIndex - 1 : start - ganZhiIndex - 1;
        if (index > 8) {
            index -= 9;
        }
        if (index < 0) {
            index += 9;
        }
        return NineStar.fromIndex(index);
    }

    public NineStar getTimeNineStar() {
        //顺逆
        String solarYmd = this.solar.toYmd();
        boolean asc = false;
        if (diff(solarYmd, this.jieQi.get("冬至").toYmd(), ">=") && diff(solarYmd, this.jieQi.get("夏至").toYmd(), "<")) {
            asc = true;
        }
        int start = asc ? 7 : 3;
        String dayZhi = this.getDayZhi();
        if ("子午卯酉".indexOf(dayZhi) > -1) {
            start = asc ? 1 : 9;
        } else if ("辰戌丑未".indexOf(dayZhi) > -1) {
            start = asc ? 4 : 6;
        }
        int index = asc ? start + this.timeZhiIndex - 1 : start - this.timeZhiIndex - 1;
        if (index > 8) {
            index -= 9;
        }
        if (index < 0) {
            index += 9;
        }
        return NineStar.fromIndex(index);
    }

    public Solar getSolar() {
        return this.solar;
    }

    public Map<String, Solar> getJieQiTable() {
        return this.jieQi;
    }

    public List<String> getJieQiList() {
        return this.jieQiList;
    }

    public JieQi getNextJie() {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = Lunar.JIE_QI_IN_USE.length / 2; i < j; i++) {
            conditions.add(Lunar.JIE_QI_IN_USE[i * 2]);
        }
        return this._getNearJieQi(true, conditions);
    }

    public JieQi getPrevJie() {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = Lunar.JIE_QI_IN_USE.length / 2; i < j; i++) {
            conditions.add(Lunar.JIE_QI_IN_USE[i * 2]);
        }
        return this._getNearJieQi(false, conditions);
    }

    public JieQi getNextQi() {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = Lunar.JIE_QI_IN_USE.length / 2; i < j; i++) {
            conditions.add(Lunar.JIE_QI_IN_USE[i * 2 + 1]);
        }
        return this._getNearJieQi(true, conditions);
    }

    public JieQi getPrevQi() {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = Lunar.JIE_QI_IN_USE.length / 2; i < j; i++) {
            conditions.add(Lunar.JIE_QI_IN_USE[i * 2 + 1]);
        }
        return this._getNearJieQi(false, conditions);
    }

    public JieQi getNextJieQi() {
        return this._getNearJieQi(true, null);
    }

    public JieQi getPrevJieQi() {
        return this._getNearJieQi(false, null);
    }

    public JieQi _buildJieQi(String name, Solar solar) {
        boolean jie = false, qi = false;
        int i, j;
        for (i = 0,
                     j = Lunar.JIE_QI.length; i < j; i++) {
            if (Objects.equals(Lunar.JIE_QI[i], name)) {
                if (i % 2 == 0) {
                    qi = true;
                } else {
                    jie = true;
                }
                break;
            }
        }
        return new JieQi(name, solar, jie, qi);
    }

    public JieQi _getNearJieQi(boolean forward, List<String> conditions) {
        String name = null;
        Solar near = null;
        Map<String, Boolean> filters = new HashMap<>();
        boolean filter = false;
        if (null != conditions) {
            for (int i = 0, j = conditions.size(); i < j; i++) {
                filters.put(conditions.get(i), true);
                filter = true;
            }
        }
        String today = this.solar.toYmdHms();
        for (String key : this.jieQi.keySet()) {
            String jq = this._convertJieQi(key);
            if (filter) {
                if (filters.get(jq)==null || !filters.get(jq)) {
                    continue;
                }
            }
            Solar solar = this.jieQi.get(key);
            String day = solar.toYmdHms();
            if (forward) {
                if (diff(day, today, "<")) {
                    continue;
                }
                if (null == near || diff(day, near.toYmdHms(), "<")) {
                    name = jq;
                    near = solar;
                }
            } else {
                if (diff(day, today, ">")) {
                    continue;
                }
                if (null == near || diff(day, near.toYmdHms(), ">")) {
                    name = jq;
                    near = solar;
                }
            }
        }

        if (null == near) {
            return null;
        }
        return this._buildJieQi(name, near);
    }

    public JieQi getCurrentJieQi() {
        String name = this.getJieQi();
        return name.length() > 0 ? this._buildJieQi(name, this.solar) : null;
    }

    public JieQi getCurrentJie() {
        String name = this.getJie();
        return name.length() > 0 ? this._buildJieQi(name, this.solar) : null;
    }

    public JieQi getCurrentQi() {
        String name = this.getQi();
        return name.length() > 0 ? this._buildJieQi(name, this.solar) : null;
    }

    public EightChar getEightChar() {
        if (this.eightChar == null) {
            this.eightChar = EightChar.fromLunar(this);
        }
        return this.eightChar;
    }

    public Lunar next(int days) {
        return this.solar.next(days, false).getLunar();
    }

    public String getYearXun() {
        return LunarUtil.getXun(this.getYearInGanZhi());
    }

    public String getMonthXun() {
        return LunarUtil.getXun(this.getMonthInGanZhi());
    }

    public String getDayXun() {
        return LunarUtil.getXun(this.getDayInGanZhi());
    }

    public String getTimeXun() {
        return LunarUtil.getXun(this.getTimeInGanZhi());
    }

    public String getYearXunByLiChun() {
        return LunarUtil.getXun(this.getYearInGanZhiByLiChun());
    }

    public String getYearXunExact() {
        return LunarUtil.getXun(this.getYearInGanZhiExact());
    }

    public String getMonthXunExact() {
        return LunarUtil.getXun(this.getMonthInGanZhiExact());
    }

    public String getDayXunExact() {
        return LunarUtil.getXun(this.getDayInGanZhiExact());
    }

    public String getDayXunExact2() {
        return LunarUtil.getXun(this.getDayInGanZhiExact2());
    }

    public String getYearXunKong() {
        return LunarUtil.getXunKong(this.getYearInGanZhi());
    }

    public String getMonthXunKong() {
        return LunarUtil.getXunKong(this.getMonthInGanZhi());
    }

    public String getDayXunKong() {
        return LunarUtil.getXunKong(this.getDayInGanZhi());
    }

    public String getTimeXunKong() {
        return LunarUtil.getXunKong(this.getTimeInGanZhi());
    }

    public String getYearXunKongByLiChun() {
        return LunarUtil.getXunKong(this.getYearInGanZhiByLiChun());
    }

    public String getYearXunKongExact() {
        return LunarUtil.getXunKong(this.getYearInGanZhiExact());
    }

    public String getMonthXunKongExact() {
        return LunarUtil.getXunKong(this.getMonthInGanZhiExact());
    }

    public String getDayXunKongExact() {
        return LunarUtil.getXunKong(this.getDayInGanZhiExact());
    }

    public String getDayXunKongExact2() {
        return LunarUtil.getXunKong(this.getDayInGanZhiExact2());
    }

    @Override
    public String toString() {
        return this.getYearInChinese() + "年" + this.getMonthInChinese() + "月" + this.getDayInChinese();
    }

    public String toSimpleString() {
        return this.getYear() + "-" + this.getMonth() + "-" + this.getDay();
    }

    public String toFullString() {
        StringBuilder s = new StringBuilder(this.toString());
        s.append(" ").append(this.getYearInGanZhi()).append("(").append(this.getYearShengXiao()).append(")年");
        s.append(" ").append(this.getMonthInGanZhi()).append("(").append(this.getMonthShengXiao()).append(")月");
        s.append(" ").append(this.getDayInGanZhi()).append("(").append(this.getDayShengXiao()).append(")日");
        s.append(" ").append(this.getTimeZhi()).append("(").append(this.getTimeShengXiao()).append(")时");
        s.append(" 纳音[").append(this.getYearNaYin()).append(" ").append(this.getMonthNaYin()).append(" ").append(this.getDayNaYin()).append(" ").append(this
                .getTimeNaYin()).append("]");
        s.append(" 星期").append(this.getWeekInChinese());
        List<String> festivals = this.getFestivals();
        int i, j;
        for (i = 0, j = festivals.size(); i < j; i++) {
            s.append(" (").append(festivals.get(i)).append(")");
        }
        List<String> otherFestivals = this.getOtherFestivals();
        for (i = 0,
                     j = otherFestivals.size(); i < j; i++) {
            s.append(" (").append(otherFestivals.get(i)).append(")");
        }
        String jq = this.getJieQi();
        if (jq.length() > 0) {
            s.append(" [").append(jq).append("]");
        }
        s.append(" ").append(this.getGong()).append("方").append(this.getShou());
        s.append(" 星宿[").append(this.getXiu()).append(this.getZheng()).append(this.getAnimal()).append("](").append(this.getXiuLuck()).append(")");
        s.append(" 彭祖百忌[").append(this.getPengZuGan()).append(" ").append(this.getPengZuZhi()).append("]");
        s.append(" 喜神方位[").append(this.getDayPositionXi()).append("](").append(this.getDayPositionXiDesc()).append(")");
        s.append(" 阳贵神方位[").append(this.getDayPositionYangGui()).append("](").append(this.getDayPositionYangGuiDesc()).append(")");
        s.append(" 阴贵神方位[").append(this.getDayPositionYinGui()).append("](").append(this.getDayPositionYinGuiDesc()).append(")");
        s.append(" 福神方位[").append(this.getDayPositionFu()).append("](").append(this.getDayPositionFuDesc()).append(")");
        s.append(" 财神方位[").append(this.getDayPositionCai()).append("](").append(this.getDayPositionCaiDesc()).append(
                ")");
        s.append(" 冲[").append(this.getDayChongDesc()).append("]");
        s.append(" 煞[").append(this.getDaySha()).append("]");
        return s.toString();
    }

    public Fu _buildNameAndIndex(String name, int index) {
        return new Fu(name, index);
    }

    public Fu getShuJiu() {
        ExactDate currentCalendar = ExactDate.fromYmd(this.solar.getYear(), this.solar.getMonth(), this.solar
                .getDay());
        Solar start = this.jieQi.get("DONG_ZHI");
        ExactDate startCalendar = ExactDate.fromYmd(start.getYear(), start.getMonth(), start.getDay());
        if (currentCalendar.getTime() < startCalendar.getTime()) {
            start = this.jieQi.get("冬至");
            startCalendar = ExactDate.fromYmd(start.getYear(), start.getMonth(), start.getDay());
        }
        ExactDate endCalendar = ExactDate.fromYmd(start.getYear(), start.getMonth(), start.getDay());
        endCalendar.setDate(endCalendar.getDate() + 81);
        if (currentCalendar.getTime() < startCalendar.getTime()
                || currentCalendar.getTime() >= endCalendar.getTime()) {
            return null;
        }
        double days =  Math.floor((currentCalendar.getTime() * 1d - startCalendar.getTime()) / MS_PER_DAY);
        return this._buildNameAndIndex(LunarUtil.NUMBER[(int) (Math.floor(days / 9) + 1)] + "九", (int) (days % 9 + 1));
    }

    public Fu getFu() {
        ExactDate currentCalendar = ExactDate.fromYmd(this.solar.getYear(), this.solar.getMonth(), this.solar
                .getDay());
        Solar xiaZhi = this.jieQi.get("夏至");
        Solar liQiu = this.jieQi.get("立秋");
        ExactDate startCalendar = ExactDate.fromYmd(xiaZhi.getYear(), xiaZhi.getMonth(), xiaZhi.getDay());

        // 第1个庚日
        int add = 6 - xiaZhi.getLunar().getDayGanIndex();
        if (add < 0) {
            add += 10;
        }
        // 第3个庚日，即初伏第1天
        add += 20;
        startCalendar.setDate(startCalendar.getDate() + add);

        // 初伏以前 currentCalendar < startCalendar
        if (currentCalendar.getTime() < startCalendar.getTime()) {
            return null;
        }

        double days = Math.floor((currentCalendar.getTime() * 1d - startCalendar.getTime()) / MS_PER_DAY);
        if (days < 10) {
            return this._buildNameAndIndex("初伏", (int) (days + 1));
        }

        // 第4个庚日，中伏第1天
        startCalendar.setDate(startCalendar.getDate() + 10);

        days = Math.floor((currentCalendar.getTime() * 1d - startCalendar.getTime()) / MS_PER_DAY);
        if (days < 10) {
            return this._buildNameAndIndex("中伏", (int) (days + 1));
        }

        // 第5个庚日，中伏第11天或末伏第1天
        startCalendar.setDate(startCalendar.getDate() + 10);

        ExactDate liQiuCalendar = ExactDate.fromYmd(liQiu.getYear(), liQiu.getMonth(), liQiu.getDay());

        days = Math.floor((currentCalendar.getTime()*1d - startCalendar.getTime()) / MS_PER_DAY);
        // 末伏
        if (liQiuCalendar.getTime() <= startCalendar.getTime()) {
            if (days < 10) {
                return this._buildNameAndIndex("末伏", (int) (days + 1));
            }
        } else {
            // 中伏
            if (days < 10) {
                return this._buildNameAndIndex("中伏", (int) (days + 11));
            }
            // 末伏第1天
            startCalendar.setDate(startCalendar.getDate() + 10);
            days = Math.floor((currentCalendar.getTime()*1d - startCalendar.getTime()) / MS_PER_DAY);
            if (days < 10) {
                return this._buildNameAndIndex("末伏", (int) (days + 1));
            }
        }
        return null;
    }

    public String getLiuYao() {
        return LunarUtil.LIU_YAO[(Math.abs(this.month) + this.day - 2) % 6];
    }

    public String getWuHou() {
        JieQi jieQi = this.getPrevJieQi();
        String name = jieQi.getName();
        int offset = 0;
        for (int i = 0, j = Lunar.JIE_QI.length; i < j; i++) {
            if (Objects.equals(name, Lunar.JIE_QI[i])) {
                offset = i;
                break;
            }
        }
        ExactDate currentCalendar = ExactDate.fromYmd(this.solar.getYear(), this.solar.getMonth(), this.solar
                .getDay());
        Solar startSolar = jieQi.getSolar();
        ExactDate startCalendar = ExactDate.fromYmd(startSolar.getYear(), startSolar.getMonth(), startSolar.getDay());
        double days = Math.floor((currentCalendar.getTime()*1d - startCalendar.getTime()) / MS_PER_DAY);
        return LunarUtil.WU_HOU[(int) ((offset * 3 + Math.floor(days / 5)) % LunarUtil.WU_HOU.length)];
    }
}
